#pragma once

#include "curlwork/curlwork.hpp"
#include "curlwork/slist.hpp"

namespace curlwork {

template<typename value_type, option_type O>
struct basic_option
{
    const value_type value_;

    explicit basic_option(const value_type& val) throw()
        : value_(val)
    {   }

    template<typename P>
    void apply(const P& p) const
    {
        set_option(p.handle(), O, value_);
    }
};

/*
    Remember libcurl takes !!!POINTER!!! to char
    watch out for the lifetime of the object
*/
typedef basic_option<const char *, CURLOPT_URL> url;
typedef basic_option<const char *, CURLOPT_USERNAME> username;
typedef basic_option<const char *, CURLOPT_PASSWORD> password;
typedef basic_option<const char *, CURLOPT_USERPWD> userpwd;
typedef basic_option<const char *, CURLOPT_COOKIE> cookie;
typedef basic_option<const char *, CURLOPT_COOKIEFILE> cookie_file;
typedef basic_option<const char *, CURLOPT_PROXY> proxy;
typedef basic_option<const char *, CURLOPT_NOPROXY> noproxy;
typedef basic_option<const char *, CURLOPT_PROXYUSERNAME> proxy_username;
typedef basic_option<const char *, CURLOPT_PROXYPASSWORD> proxy_password;
typedef basic_option<const char *, CURLOPT_PROXYUSERPWD> proxy_userpwd;
typedef basic_option<const char *, CURLOPT_TLSAUTH_USERNAME> tlsauth_username;
typedef basic_option<const char *, CURLOPT_TLSAUTH_PASSWORD> tlsauth_password;
typedef basic_option<const char *, CURLOPT_REFERER> referer;
typedef basic_option<const char *, CURLOPT_USERAGENT> user_agent;
typedef basic_option<char *, CURLOPT_ERRORBUFFER> error_buffer;
typedef basic_option<FILE *, CURLOPT_STDERR> stderr;
typedef basic_option<const char *, CURLOPT_SOCKS5_GSSAPI_SERVICE>
    socks5_gssapi_service;
typedef basic_option<const char *, CURLOPT_INTERFACE> interface;
typedef basic_option<const char *, CURLOPT_NETRC_FILE> netrc_file;
typedef basic_option<const char *, CURLOPT_MAIL_FROM> mail_from;
typedef basic_option<const char *, CURLOPT_MAIL_AUTH> mail_auth;
typedef basic_option<const char *, CURLOPT_FTP_ALTERNATIVE_TO_USER>
    ftp_alternative_to_user;
typedef basic_option<const char *, CURLOPT_FTP_ACCOUNT> ftp_account;

typedef basic_option<delegate*, CURLOPT_PRIVATE> binder;

struct option
{
    const option_type opt_;
    const long value_;

    explicit option(const option_type opt, const long val) throw()
        : opt_(opt)
        , value_(val)
    {   }

    template<typename P>
    void apply(const P& p) const
    {
        set_option(p.handle(), opt_, value_);
    }
};

// http://curl.haxx.se/libcurl/c/http-post.html
struct post
{
    const char *buffer_;
    bool copy_;

    explicit post(const char *buffer, bool copy = true) throw()
        : buffer_(buffer)
        , copy_(copy)
    {   }

    template<typename P>
    void apply(const P& p) const
    {
        set_option(p.handle(),
                   (copy_) ? CURLOPT_COPYPOSTFIELDS : CURLOPT_POSTFIELDS,
                   buffer_);
    }
};

typedef basic_slist<CURLOPT_HTTPHEADER> http_header;
typedef basic_slist<CURLOPT_HTTP200ALIASES> http_alias;
typedef basic_slist<CURLOPT_MAIL_RCPT> mail_rcpt;
typedef basic_slist<CURLOPT_QUOTE> quote;
typedef basic_slist<CURLOPT_POSTQUOTE> post_quote;
typedef basic_slist<CURLOPT_PREQUOTE> pre_quote;
typedef basic_slist<CURLOPT_RESOLVE> resolve;
typedef basic_slist<CURLOPT_TELNETOPTIONS> telnet_options;

} // namespace curlwork

